import java.util.*;

public class MFQS {
    //首先定义PCB的结构，定义为静态内部类
    static class Process implements Comparable<Process>{
       public String id;//存储进程的ID
       public int arriveTime;//存储进程到达时间
       public int executionTime;//存储进程的执行时间
       public int remainTime;  //存储进程的剩余的执行时间
       public String state;    //进程状态ready就绪/run执行/finish完成

        @Override
        public String toString() {
            return "Process{" +
                    "id='" + id + '\'' +
                    ", arriveTime=" + arriveTime +
                    ", executionTime=" + executionTime +
                    ", remainTime=" + remainTime +
                    ", state='" + state + '\'' +
                    '}';
        }

        @Override
        //重写比较器，比较哪个线程优先级更高
        public int compareTo(Process o) {
            return Integer.compare(this.arriveTime, o.arriveTime);
        }
    }
    //定义三个就绪队列
    public static Queue<Process> firstQueue=new LinkedList<>();//第1级队列
    public static Queue<Process> secondQueue=new LinkedList<>();//第2级队列
    public static Queue<Process> thirdQueue=new LinkedList<>();//第3级队列
    public static int proNum;//总进程数量
    //存储后续需要调度的数组
    public static Process[] pro = new Process[proNum];//存放进程的数组
    //每个队列的时间片大小
    public static int firstTime;
    public static int secondTime;
    public static int thirdTime;

    public static void multiStageFeedbackQueueScheduling(Process[] process){
        int currenttime=0;//定义当前时间为0
        int num=0;//定义当前加入队列的是第多少个
        //记录下每个时间片大小，方便后续恢复
        int firstCpu = firstTime ;
        int secondCpu =  secondTime;
        int thirdCpu = thirdTime ;
        //当有进程未运行时或进程队列不为空时，进行调度
        while(num<proNum||!firstQueue.isEmpty()||!secondQueue.isEmpty()||!thirdQueue.isEmpty()){
            //当有进程未运行并且该进程到来了,就把该进程加入优先级最高的队列，并且向后轮转
            while(num<proNum&&pro[num].arriveTime==currenttime){
                firstQueue.add(pro[num++]);
            }
            //打印上一秒的各队列状态
            show(currenttime);
            //如果一开始时间为0没有来进程，则直接时间向后走
            if(firstQueue.isEmpty()){
                currenttime++;
            }
            //如果第一个队列不为空
            if(!firstQueue.isEmpty()){
                //如果另外两个队列不为空，全部让其处于就绪状态，低优先级不能抢占
                if(secondQueue.peek()!=null){
                    secondQueue.peek().state="Ready";
                }
                if(thirdQueue.peek()!=null){
                    thirdQueue.peek().state="Ready";
                }
                //仍需时间：-1
                firstQueue.peek().remainTime-=1;
                //CPU剩余时间片：-1
                firstTime -= 1;
                //更新当前时间：+1
                currenttime+=1;
                //如果进程还有剩余时间，那么处于执行状态
               if(firstQueue.peek().remainTime>0){
                   firstQueue.peek().state = "Run";
                   //时间片用完了回到就绪队列
                   if(firstTime==0){
                       firstQueue.peek().state="Ready";
                       //插入到第二个队列中（下一优先级队列中)
                       secondQueue.add(firstQueue.poll());
                       firstTime=firstCpu;
                   }//如果进程不剩时间，直接结束
               }else if(firstQueue.peek().remainTime==0){
                   firstQueue.peek().state="Finish";
                   System.out.printf("\n当前时刻：%d,此进程运行结束：\n",currenttime);
                   System.out.println(firstQueue.peek());
                   Objects.requireNonNull(firstQueue.poll());
                   firstTime = firstCpu;
               }
            }else if(!secondQueue.isEmpty()){
                if(thirdQueue.peek()!=null){
                    thirdQueue.peek().state="Ready";
                }
                //仍需时间：-1
                secondQueue.peek().remainTime -= 1;
                //CPU剩余时间片：-1
                secondTime -= 1;
                //更新当前时间：+1
                currenttime++;
                if(secondQueue.peek().remainTime>0){
                    secondQueue.peek().state="Run";
                    if(secondTime==0){
                        secondQueue.peek().state="Ready";
                        thirdQueue.add(secondQueue.poll());
                        secondTime=secondCpu;
                    }
                }else if(secondQueue.peek().remainTime==0){
                    secondQueue.peek().state="Finish";
                    System.out.printf("\n当前时刻：%d,此进程运行结束：\n",currenttime);
                    System.out.println(secondQueue.peek());
                    Objects.requireNonNull(secondQueue.poll());
                    secondTime = secondCpu;
                }
            }else if(!thirdQueue.isEmpty()){
                //仍需时间：-1
                thirdQueue.peek().remainTime -= 1;
                //CPU剩余时间片：-1
                thirdTime -= 1;
                //更新当前时间：+1
                currenttime++;

                //进程正在运行，状态：R.
                if(thirdQueue.peek().remainTime>0){
                    thirdQueue.peek().state = "Run";
                    //当前队列CPU时间片用完而进程仍未运行完时，进程出队，入次优先级队尾
                    if(thirdTime==0){
                        thirdQueue.peek().state = "Ready";
                        thirdQueue.add(thirdQueue.poll());
                        thirdTime = thirdCpu;
                    }
                }  else if(thirdQueue.peek().remainTime==0){
                    thirdQueue.peek().state = "Finish";
                    System.out.printf("\n当前时刻：%d,此进程运行结束：\n",currenttime);
                    System.out.println(thirdQueue.peek());
                    Objects.requireNonNull(thirdQueue.poll());
                    thirdTime=thirdCpu;
                }
            }
        }
    }
    //输入面板：获取到进程数组pro

    public static Process[] operator(){
        System.out.println("-----------------G12214082 陈梅霞-----------------");
        System.out.println("欢迎进入多级队列反馈调度模拟系统，队列个数：3。");
        Scanner scanner = new Scanner(System.in);
        System.out.print( "请输入进程数:" );
        proNum = scanner.nextInt();
        /*获取到进程数组*/
        Process[] pro = new Process[proNum];
        System.out.println( "请输入三个队列时间片大小分别为:" );
        firstTime=scanner.nextInt();
        secondTime=scanner.nextInt();
        thirdTime=scanner.nextInt();
        System.out.println( "请依次输入进程标识符,进程到达时间,和进程所需运行时间:" );
        for( int i = 0; i < proNum; i++ ) {
            pro[i] = new Process();
            pro[i].id = scanner.next();
            pro[i].arriveTime = scanner.nextInt();
            pro[i].executionTime = scanner.nextInt();
            pro[i].remainTime = pro[i].executionTime;
            pro[i].state = "Ready";
        }
        //对进程按照compareTo()的要求按照到达时间排序
        Arrays.sort(pro);
        return pro;
    }


    //输出面板：实时输出进程队列结果
    public static void show(int currenttime){
        System.out.println("==========================================");
        System.out.println("当前时间为："+currenttime);
        System.out.println("==========================================");
        System.out.println("到达时间   运行时间   剩余时间");
        if(firstQueue.isEmpty()){
            System.out.println("队列1：null");
        }else{
            System.out.println("队列1："+firstQueue.toString());
        }
        if(secondQueue.isEmpty()){
            System.out.println("队列2：null");
        }else{
            System.out.println("队列2："+secondQueue.toString());
        }
        if(thirdQueue.isEmpty()){
            System.out.println("队列3：null");
        }else{
            System.out.println("队列3："+thirdQueue.toString());
        }
    }

    public static void main(String[] args) {
        MFQS.pro=operator();
       multiStageFeedbackQueueScheduling(MFQS.pro);

    }
}
